package com.hmdp.service.impl;

import com.hmdp.dto.Result;
import com.hmdp.entity.SeckillVoucher;
import com.hmdp.entity.VoucherOrder;
import com.hmdp.mapper.VoucherOrderMapper;
import com.hmdp.service.IVoucherOrderService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.hmdp.utils.RedisWorker;
import com.hmdp.utils.SimpleRedisLock;
import com.hmdp.utils.UserHolder;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.aop.framework.AopContext;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.time.LocalDateTime;

/**
 * <p>
 *  服务实现类
 * </p>
 *
 * @author 虎哥
 * @since 2021-12-22
 */
@Service
public class VoucherOrderServiceImpl extends ServiceImpl<VoucherOrderMapper, VoucherOrder> implements IVoucherOrderService {


    @Resource
    private SeckillVoucherServiceImpl seckillVoucherService;

    @Resource
    private RedisWorker redisWorker;

    @Resource
    private StringRedisTemplate stringRedisTemplate;

    @Resource
    private RedissonClient redissonClient;
    /**
     * 优惠券秒杀
     * @param voucherId  优惠券id
     * @return
     */

    @Override
    public Result seckillVoucher(Long voucherId) {
        SeckillVoucher sv = seckillVoucherService.getById(voucherId);
        if (sv.getBeginTime().isAfter(LocalDateTime.now())){
            return Result.fail("还未开始！");
        }
        if (LocalDateTime.now().isAfter(sv.getEndTime())){
            return Result.fail("已经结束！");
        }
        if (sv.getStock()<1) {
            return Result.fail("库存不足！");
        }
        //实现一人一单
        Long user_id = UserHolder.getUser().getId();
        /*通过user_id.toString()实现，每一个用户对应同一把锁，避免同一个用户重复创建订单
           而使用intern方法是因为，每次toString其实生成的是不同的对象，而使用了intern方法，就是从常量池中拿对象，保证每个user_id对应的对象是同一个
         */
        /*synchronized (user_id.toString().intern()){
            //获取当前对象的代理对象，调用代理对象的createVoucherOrder方法，才会使事务生效
            IVoucherOrderService ios_proxy = (IVoucherOrderService)AopContext.currentProxy();
            return  ios_proxy.createVoucherOrder(voucherId);
        }

        //使用redis实现分布式锁
        SimpleRedisLock simpleRedisLock = new SimpleRedisLock("order:"+user_id,stringRedisTemplate);
        boolean success = simpleRedisLock.tryLock(3);
        if (!success){
            return Result.fail("不允许重复下单");
        }
        try {
            IVoucherOrderService o = (IVoucherOrderService)AopContext.currentProxy();
            return o.createVoucherOrder(voucherId);
        }finally {
            simpleRedisLock.unLock();
        }*/

        //使用redisson作为分布式锁
        RLock lock = redissonClient.getLock("lock:order" + user_id);
        boolean success = lock.tryLock();
        if (!success){
            return Result.fail("不允许重复下单！");
        }
        try{
            IVoucherOrderService o = (IVoucherOrderService)AopContext.currentProxy();
            return o.createVoucherOrder(voucherId);
        }finally {
            lock.unlock();
        }
    }


    @Transactional
    public Result createVoucherOrder(Long voucherId) {
            Long userid = UserHolder.getUser().getId();
            int count = query().eq("user_id", userid).eq("voucher_id", voucherId).count();
            if (count > 0) {
                return Result.fail("已经购买过，无法重复购买！");
            }
            //where id = ? and stock > 0,使用mysql的乐观锁解决超卖问题
            boolean success = seckillVoucherService.update().setSql("stock=stock-1").eq("voucher_id", voucherId)
                    .gt("stock", 0).update();
            if (!success)
                return Result.fail("库存不足！");
            //购买成功，创建订单信息
            VoucherOrder voucherOrder = new VoucherOrder();
            //订单id
            //使用全局id生成器生成
            long id = redisWorker.nextId("order");
            voucherOrder.setId(id);
            //用户id
            voucherOrder.setUserId(UserHolder.getUser().getId());
            //优惠卷id
            voucherOrder.setVoucherId(voucherId);
            //生成订单
            boolean s = save(voucherOrder);
            System.out.println(s);
            //返回
            return Result.ok("购买成功！");
    }
}
